pinctrl子系统

您所在的位置:网站首页 form create源码解析 pinctrl子系统

pinctrl子系统

2024-02-02 20:50| 来源: 网络整理| 查看: 265

一,pincontroller (pinctrl server)构造 1,pin controller driver与 device match并执行probe diwali_pinctrl_init platform_driver_register(&diwali_pinctrl_driver); //根据match table找到device diwali_pinctrl_probe pinctrl_data = of_device_get_match_data(&pdev->dev);//获取msm_pinctrl_soc_data msm_pinctrl_probe(pdev, pinctrl_data);//传递soc data 2,probe流程 int msm_pinctrl_probe(struct platform_device *pdev, const struct msm_pinctrl_soc_data *soc_data) { // 1)分配一个msm_pinctrl结构并初始化 msm_pinctrl_data = pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); if (!pctrl) return -ENOMEM; pctrl->dev = &pdev->dev; pctrl->soc = soc_data; pctrl->chip = msm_gpio_template; pctrl->intr_target_use_scm = of_device_is_compatible( pctrl->dev->of_node, "qcom,ipq8064-pinctrl"); // 2)从pin controller device dts节点中获取设备的物理地址 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENOENT; //将设备的物理地址转换为虚拟地址,使用该地址读写该pin controller device pctrl->regs[0] = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(pctrl->regs[0])) return PTR_ERR(pctrl->regs[0]); pctrl->phys_base[0] = res->start; //3)从pin controller device dts节点中获取irq number pctrl->irq = platform_get_irq(pdev, 0); if (pctrl->irq < 0) return pctrl->irq; //4) 构造一个pinctrl_desc pctrl->desc.owner = THIS_MODULE; //引脚枚举与命名 pctrl->desc.pctlops = &msm_pinctrl_ops; //引脚复用 pctrl->desc.pmxops = &msm_pinmux_ops; //引脚配置 pctrl->desc.confops = &msm_pinconf_ops; pctrl->desc.name = dev_name(&pdev->dev); //soc data提供 pctrl->desc.pins = pctrl->soc->pins; pctrl->desc.npins = pctrl->soc->npins; pctrl->desc.num_custom_params = ARRAY_SIZE(msm_gpio_bindings); pctrl->desc.custom_params = msm_gpio_bindings; //根据pinctrl_desc信息构造一个pinctrl_dev pctrl->pctrl = devm_pinctrl_register(&pdev->dev, &pctrl->desc, pctrl); if (IS_ERR(pctrl->pctrl)) { dev_err(&pdev->dev, "Couldn't register pinctrl driver\n"); return PTR_ERR(pctrl->pctrl); } //5) ret = msm_gpio_init(pctrl); if (ret) return ret; platform_set_drvdata(pdev, pctrl); }

pin controller描述符中包括了三类操作函数:pctlops是一些全局的控制函数,pmxops是复用引脚相关的操作函数,confops操作函数是用来配置引脚的特性(例如:pull-up/down)。这些callback函数都是和具体的底层pin controller的操作相关,qcom平台pinctrl controller low level driver实现的API如下,每一个的实现请查看kernel开源代码pinctrl-msm.c:

1)struct pinctrl_ops

static const struct pinctrl_ops msm_pinctrl_ops = { .get_groups_count = msm_get_groups_count, .get_group_name = msm_get_group_name, .get_group_pins = msm_get_group_pins, .dt_node_to_map = pinconf_generic_dt_node_to_map_group, .dt_free_map = pinctrl_utils_free_map, };

2)struct pinmux_ops

static const struct pinmux_ops msm_pinmux_ops = { .request = msm_pinmux_request, .get_functions_count = msm_get_functions_count, .get_function_name = msm_get_function_name, .get_function_groups = msm_get_function_groups, .gpio_request_enable = msm_pinmux_request_gpio, .set_mux = msm_pinmux_set_mux, };

3)struct pinconf_ops

static const struct pinconf_ops msm_pinconf_ops = { .is_generic = true, .pin_config_group_get = msm_config_group_get, .pin_config_group_set = msm_config_group_set, }; 3,devm_pinctrl_register()流程 pctrl->pctrl = devm_pinctrl_register(&pdev->dev, &pctrl->desc, pctrl); pctldev = pinctrl_register(pctldesc, dev, driver_data); pinctrl_init_controller(pctldesc, dev, driver_data); //给pinctrl_dev分配内存 pctldev = kzalloc(sizeof(*pctldev), GFP_KERNEL); // driver_data是msm_pinctrl pctldev->driver_data = driver_data; //check core ops for sanity pinctrl_check_ops(pctldev); //If we're implementing pinmuxing, check the ops for sanity pinmux_check_ops(pctldev); //If we're implementing pinconfig, check the ops for sanity pinconf_check_ops(pctldev); pinctrl_register_pins(pctldev, pctldesc->pins, pctldesc->npins); pinctrl_enable(pctldev); //将pinctrl_dev加入pinctrldev_list链表 list_add_tail(&pctldev->node, &pinctrldev_list); //在每一个pin controller device的目录中生成pinctrl调试节点,eg:/sys/kernel/debug/pinctrl/f000000.pinctrl pinctrl_init_device_debugfs(pctldev); debugfs_create_file("pins", S_IFREG | S_IRUGO, device_root, pctldev, &pinctrl_pins_fops); debugfs_create_file("pingroups", S_IFREG | S_IRUGO, device_root, pctldev, &pinctrl_groups_fops); debugfs_create_file("gpio-ranges", S_IFREG | S_IRUGO, device_root, pctldev, &pinctrl_gpioranges_fops); 二,client端使用pinctrl的过程 1,dev_pin_info

设备节点要么被转换为platform_device,或者其他结构体(比如i2c_client),但是里面都会有一个device结构体,每个device结构体里都有一个dev_pin_info结构体,用来保存设备的pinctrl信息。

platform_device匹配driver会执行probe探测函数,执行到驱动中真正的probe函数之前,会进行pinctrl的处理,处理函数为pinctrl_bind_pins。

really_probe() pinctrl_bind_pins(dev); devm_pinctrl_get(dev); pinctrl_get(dev); create_pinctrl(dev, NULL); //把dts中该设备的pinctrl配置解析到pinctrl map中 pinctrl_dt_to_map(p, pctldev); dt_to_map_one_config(p, pctldev, statename, np_config); ops->dt_node_to_map(pctldev, np_config, &map, &num_maps); .dt_node_to_map = pinconf_generic_dt_node_to_map_group, pinconf_generic_dt_node_to_map //pinctrl map mux pinctrl_utils_add_map_mux //pinctrl map configs pinctrl_utils_add_map_configs //把pinctrl map 转为pinctrl setting add_setting(p, pctldev, map); pinmux_map_to_setting(map, setting); pinconf_map_to_setting(map, setting); list_add_tail(&setting->node, &state->settings); //该设备的pinctrl state holder挂到pinctrl_list链表 list_add_tail(&p->node, &pinctrl_list); //解析标准的pinctrl state,PINCTRL_STATE_DEFAULT/PINCTRL_STATE_INIT/PINCTRL_STATE_SLEEP/PINCTRL_STATE_IDLE dev->pins->default_state = pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_DEFAULT); dev->pins->init_state = pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_INIT); pinctrl_select_state(dev->pins->p, dev->pins->default_state); dev->pins->sleep_state = pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_SLEEP); dev->pins->idle_state = pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_IDLE); //执行device或者driver的probe函数 dev->bus->probe(dev); drv->probe(dev); 2,pinctrl debugfs 2.1 一个pin controller device --- f000000.pinctrl ls -l /sys/kernel/debug/pinctrl/f000000.pinctrl -r--r--r-- 1 root root 0 1970-01-01 00:00 gpio-ranges -r--r--r-- 1 root root 0 1970-01-01 00:00 pinconf-groups -r--r--r-- 1 root root 0 1970-01-01 00:00 pinconf-pins -r--r--r-- 1 root root 0 1970-01-01 00:00 pingroups -r--r--r-- 1 root root 0 1970-01-01 00:00 pinmux-functions -r--r--r-- 1 root root 0 1970-01-01 00:00 pinmux-pins -r--r--r-- 1 root root 0 1970-01-01 00:00 pins

系统中注册的所有的pinctrl controller,打印接口:

static int pinctrl_devices_show(struct seq_file *s, void *what) { struct pinctrl_dev *pctldev; seq_puts(s, "name [pinmux] [pinconf]\n"); mutex_lock(&pinctrldev_list_mutex); list_for_each_entry(pctldev, &pinctrldev_list, node) { seq_printf(s, "%s ", pctldev->desc->name); if (pctldev->desc->pmxops) seq_puts(s, "yes "); else seq_puts(s, "no "); if (pctldev->desc->confops) seq_puts(s, "yes"); else seq_puts(s, "no"); seq_puts(s, "\n"); } mutex_unlock(&pinctrldev_list_mutex); return 0; } DEFINE_SHOW_ATTRIBUTE(pinctrl_devices);

cat /sys/kernel/debug/pinctrl/pinctrl-devices:

name [pinmux] [pinconf] f000000.pinctrl yes yes c42d000.qcom,spmi:qcom,pmk8350@0:pinctrl@b000 yes yes c42d000.qcom,spmi:qcom,pm8350c@2:pinctrl@8800 yes yes c42d000.qcom,spmi:qcom,pm7325@1:pinctrl@8800 yes yes c42d000.qcom,spmi:qcom,pm8350b@3:pinctrl@8800 yes yes soc:spf_core_platform:lpi_pinctrl@3440000 yes yes 2.2 pinctrl maps信息打印接口 static int pinctrl_maps_show(struct seq_file *s, void *what) { struct pinctrl_maps *maps_node; int i; const struct pinctrl_map *map; seq_puts(s, "Pinctrl maps:\n"); mutex_lock(&pinctrl_maps_mutex); for_each_maps(maps_node, i, map) { seq_printf(s, "device %s\nstate %s\ntype %s (%d)\n", map->dev_name, map->name, map_type(map->type), map->type); if (map->type != PIN_MAP_TYPE_DUMMY_STATE) seq_printf(s, "controlling device %s\n", map->ctrl_dev_name); switch (map->type) { case PIN_MAP_TYPE_MUX_GROUP: pinmux_show_map(s, map); break; case PIN_MAP_TYPE_CONFIGS_PIN: case PIN_MAP_TYPE_CONFIGS_GROUP: pinconf_show_map(s, map); break; default: break; } seq_putc(s, '\n'); } mutex_unlock(&pinctrl_maps_mutex); return 0; } DEFINE_SHOW_ATTRIBUTE(pinctrl_maps);

pinctrl client 节点举例:

//一个device的pinctrl state配置 xxx@xx { pinctrl-names = "pmx_ts_active", "pmx_ts_suspend", "pmx_ts_release"; pinctrl-0 = ; pinctrl-1 = ; pinctrl-2 = ; };

pinctrl server 端的配置见上一篇文章,解析后的pinctrl maps信息:

cat /sys/kernel/debug/pinctrl/pinctrl-maps

device spi1.0 state pmx_ts_active type MUX_GROUP (2) controlling device f000000.pinctrl group gpio129 function gpio device spi1.0 state pmx_ts_active type MUX_GROUP (2) controlling device f000000.pinctrl group gpio51 function gpio device spi1.0 state pmx_ts_active type CONFIGS_GROUP (4) controlling device f000000.pinctrl group gpio129 config 00000105 config 00000809 device spi1.0 state pmx_ts_active type CONFIGS_GROUP (4) controlling device f000000.pinctrl group gpio51 config 00000105 config 00000809 device spi1.0 state pmx_ts_suspend type MUX_GROUP (2) controlling device f000000.pinctrl group gpio51 function gpio device spi1.0 state pmx_ts_suspend type CONFIGS_GROUP (4) controlling device f000000.pinctrl group gpio51 config 00000103 config 00000209 device spi1.0 state pmx_ts_suspend type MUX_GROUP (2) controlling device f000000.pinctrl group gpio129 function gpio device spi1.0 state pmx_ts_suspend type CONFIGS_GROUP (4) controlling device f000000.pinctrl group gpio129 config 00000103 config 00000209 device spi1.0 state pmx_ts_release type MUX_GROUP (2) controlling device f000000.pinctrl group gpio129 function gpio device spi1.0 state pmx_ts_release type MUX_GROUP (2) controlling device f000000.pinctrl group gpio51 function gpio device spi1.0 state pmx_ts_release type CONFIGS_GROUP (4) controlling device f000000.pinctrl group gpio129 config 00000001 config 00000209 device spi1.0 state pmx_ts_release type CONFIGS_GROUP (4) controlling device f000000.pinctrl group gpio51 config 00000001 config 00000209 2.3 pinctrl setting信息打印接口 static int pinctrl_show(struct seq_file *s, void *what) { struct pinctrl *p; struct pinctrl_state *state; struct pinctrl_setting *setting; seq_puts(s, "Requested pin control handlers their pinmux maps:\n"); mutex_lock(&pinctrl_list_mutex); list_for_each_entry(p, &pinctrl_list, node) { seq_printf(s, "device: %s current state: %s\n", dev_name(p->dev), p->state ? p->state->name : "none"); list_for_each_entry(state, &p->states, node) { seq_printf(s, " state: %s\n", state->name); list_for_each_entry(setting, &state->settings, node) { struct pinctrl_dev *pctldev = setting->pctldev; seq_printf(s, " type: %s controller %s ", map_type(setting->type), pinctrl_dev_get_name(pctldev)); switch (setting->type) { case PIN_MAP_TYPE_MUX_GROUP: pinmux_show_setting(s, setting); break; case PIN_MAP_TYPE_CONFIGS_PIN: case PIN_MAP_TYPE_CONFIGS_GROUP: pinconf_show_setting(s, setting); break; default: break; } } } } mutex_unlock(&pinctrl_list_mutex); return 0; } DEFINE_SHOW_ATTRIBUTE(pinctrl);

上一节pinctrl maps转成的pinctrl settings信息打印:

cat /sys/kernel/debug/pinctrl/pinctrl-handles

device: spi1.0 current state: pmx_ts_active state: pmx_ts_active type: MUX_GROUP controller f000000.pinctrl group: gpio129 (129) function: gpio (0) type: MUX_GROUP controller f000000.pinctrl group: gpio51 (51) function: gpio (0) type: CONFIGS_GROUP controller f000000.pinctrl group gpio129 (129)config 00000105 config 00000809 type: CONFIGS_GROUP controller f000000.pinctrl group gpio51 (51)config 00000105 config 00000809 state: pmx_ts_suspend type: MUX_GROUP controller f000000.pinctrl group: gpio51 (51) function: gpio (0) type: CONFIGS_GROUP controller f000000.pinctrl group gpio51 (51)config 00000103 config 00000209 type: MUX_GROUP controller f000000.pinctrl group: gpio129 (129) function: gpio (0) type: CONFIGS_GROUP controller f000000.pinctrl group gpio129 (129)config 00000103 config 00000209 state: pmx_ts_release type: MUX_GROUP controller f000000.pinctrl group: gpio129 (129) function: gpio (0) type: MUX_GROUP controller f000000.pinctrl group: gpio51 (51) function: gpio (0) type: CONFIGS_GROUP controller f000000.pinctrl group gpio129 (129)config 00000001 config 00000209 type: CONFIGS_GROUP controller f000000.pinctrl group gpio51 (51)config 00000001 config 00000209 3,设备树节点转换为pinctrl_map

pinctrl_dt_to_map:

int pinctrl_dt_to_map(struct pinctrl *p, struct pinctrl_dev *pctldev) { struct device_node *np = p->dev->of_node; int state, ret; char *propname; struct property *prop; const char *statename; const __be32 *list; int size, config; phandle phandle; struct device_node *np_config; /* CONFIG_OF enabled, p->dev not instantiated from DT */ if (!np) { if (of_have_populated_dt()) dev_dbg(p->dev, "no of_node; not parsing pinctrl DT\n"); return 0; } /* We may store pointers to property names within the node */ of_node_get(np); /* For each defined state ID */ //遍历所有的state ID for (state = 0; ; state++) { /* Retrieve the pinctrl-* property */ propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state); if (!propname) return -ENOMEM; prop = of_find_property(np, propname, &size); kfree(propname); if (!prop) { if (state == 0) { of_node_put(np); return -ENODEV; } break; } list = prop->value; //一个state对应的config的数量 size /= sizeof(*list); /* Determine whether pinctrl-names property names the state */ //从pinctrl-names中获取statename ret = of_property_read_string_index(np, "pinctrl-names", state, &statename); /* * If not, statename is just the integer state ID. But rather * than dynamically allocate it and have to free it later, * just point part way into the property name for the string. */ if (ret < 0) statename = prop->name + strlen("pinctrl-"); /* For every referenced pin configuration node in it */ //遍历每一个state下面的每一个config for (config = 0; config < size; config++) { phandle = be32_to_cpup(list++); /* Look up the pin configuration node */ np_config = of_find_node_by_phandle(phandle); if (!np_config) { dev_err(p->dev, "prop %s index %i invalid phandle\n", prop->name, config); ret = -EINVAL; goto err; } /* Parse the node */ //对于一个config节点的解析函数 ret = dt_to_map_one_config(p, pctldev, statename, np_config); of_node_put(np_config); if (ret < 0) goto err; } /* No entries in DT? Generate a dummy state table entry */ if (!size) { ret = dt_remember_dummy_state(p, statename); if (ret < 0) goto err; } } return 0; err: pinctrl_dt_free_maps(p); return ret; }

dt_to_map_one_config:

static int dt_to_map_one_config(struct pinctrl *p, struct pinctrl_dev *hog_pctldev, const char *statename, struct device_node *np_config) { struct pinctrl_dev *pctldev = NULL; struct device_node *np_pctldev; const struct pinctrl_ops *ops; int ret; struct pinctrl_map *map; unsigned num_maps; bool allow_default = false; /* Find the pin controller containing np_config */ np_pctldev = of_node_get(np_config); for (;;) { //找到pctldev pctldev = get_pinctrl_dev_from_of_node(np_pctldev); } of_node_put(np_pctldev); /* * Call pinctrl driver to parse device tree node, and * generate mapping table entries */ ops = pctldev->desc->pctlops; if (!ops->dt_node_to_map) { dev_err(p->dev, "pctldev %s doesn't support DT\n", dev_name(pctldev->dev)); return -ENODEV; } //调用pinctrl driver中实现的dt_node_to_map ret = ops->dt_node_to_map(pctldev, np_config, &map, &num_maps); /* Stash the mapping table chunk away for later use */ //保存解析出来的pinctrl maps return dt_remember_or_free_map(p, statename, pctldev, map, num_maps); }

保存解析出来的pinctrl maps,pinctrldt_remember_or_free_map:

dt_remember_or_free_map list_add_tail(&dt_map->node, &p->dt_maps); pinctrl_register_mappings(map, num_maps); list_add_tail(&maps_node->node, &pinctrl_maps); 4,pinctrl map to pinctrl setting流程 mutex_lock(&pinctrl_maps_mutex); /* Iterate over the pin control maps to locate the right ones */ //取出pinctrl_maps链表中的每一个node,遍历每一个node中的&_maps_node_->maps[_i_] (指向struct pinctrl_map的map指针) for_each_maps(maps_node, i, map) { /* Map must be for this device */ if (strcmp(map->dev_name, devname)) continue; /* * If pctldev is not null, we are claiming hog for it, * that means, setting that is served by pctldev by itself. * * Thus we must skip map that is for this device but is served * by other device. */ if (pctldev && strcmp(dev_name(pctldev->dev), map->ctrl_dev_name)) continue; //一个map转为一个setting ret = add_setting(p, pctldev, map); /* * At this point the adding of a setting may: * * - Defer, if the pinctrl device is not yet available * - Fail, if the pinctrl device is not yet available, * AND the setting is a hog. We cannot defer that, since * the hog will kick in immediately after the device * is registered. * * If the error returned was not -EPROBE_DEFER then we * accumulate the errors to see if we end up with * an -EPROBE_DEFER later, as that is the worst case. */ if (ret == -EPROBE_DEFER) { pinctrl_free(p, false); mutex_unlock(&pinctrl_maps_mutex); return ERR_PTR(ret); } } mutex_unlock(&pinctrl_maps_mutex);

add_setting:

static int add_setting(struct pinctrl *p, struct pinctrl_dev *pctldev, const struct pinctrl_map *map) { struct pinctrl_state *state; struct pinctrl_setting *setting; int ret; //首先在struct pinctrl结构体中查找该state是否存在,list_for_each_entry(state, &p->states, node) state = find_state(p, map->name); if (!state) //如果state不存在就新建一个state,list_add_tail(&state->node, &p->states); state = create_state(p, map->name); if (IS_ERR(state)) return PTR_ERR(state); if (map->type == PIN_MAP_TYPE_DUMMY_STATE) return 0; //给struct pinctrl_setting分配内存空间 setting = kzalloc(sizeof(*setting), GFP_KERNEL); if (!setting) return -ENOMEM; //初始化setting结构体 setting->type = map->type; if (pctldev) setting->pctldev = pctldev; else setting->pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name); if (!setting->pctldev) { kfree(setting); /* Do not defer probing of hogs (circular loop) */ if (!strcmp(map->ctrl_dev_name, map->dev_name)) return -ENODEV; /* * OK let us guess that the driver is not there yet, and * let's defer obtaining this pinctrl handle to later... */ dev_info(p->dev, "unknown pinctrl device %s in map entry, deferring probe", map->ctrl_dev_name); return -EPROBE_DEFER; } setting->dev_name = map->dev_name; switch (map->type) { case PIN_MAP_TYPE_MUX_GROUP: //pinmux map to setting ret = pinmux_map_to_setting(map, setting); break; case PIN_MAP_TYPE_CONFIGS_PIN: case PIN_MAP_TYPE_CONFIGS_GROUP: //pin configure map to setting ret = pinconf_map_to_setting(map, setting); break; default: ret = -EINVAL; break; } if (ret < 0) { kfree(setting); return ret; } //将转化后的setting挂到state->settings链表 list_add_tail(&setting->node, &state->settings); return 0; }

pinmux_map_to_setting:

int pinmux_map_to_setting(const struct pinctrl_map *map, struct pinctrl_setting *setting) { struct pinctrl_dev *pctldev = setting->pctldev; const struct pinmux_ops *pmxops = pctldev->desc->pmxops; char const * const *groups; unsigned num_groups; int ret; ret = pinmux_func_name_to_selector(pctldev, map->data.mux.function); setting->data.mux.func = ret; ret = pmxops->get_function_groups(pctldev, setting->data.mux.func, &groups, &num_groups); if (ret < 0) { dev_err(pctldev->dev, "can't query groups for function %s\n", map->data.mux.function); return ret; } ret = pinctrl_get_group_selector(pctldev, group); if (ret < 0) { dev_err(pctldev->dev, "invalid group %s in map table\n", map->data.mux.group); return ret; } setting->data.mux.group = ret; return 0; }

map 到 setting的转化只是将字符串转为整型数表示的形式。

5,client节点如何使用设置管脚 really_probe pinctrl_bind_pins /* 寻找state */ pinctrl_lookup_state /* 选择state */ pinctrl_select_state pinctrl_commit_state /* 遍历settings链表 */ list_for_each_entry(setting, &state->settings, node) { switch (setting->type) { case PIN_MAP_TYPE_MUX_GROUP: /* 设置复用 */ pinmux_enable_setting(setting); ops->set_mux(...); case PIN_MAP_TYPE_CONFIGS_PIN: case PIN_MAP_TYPE_CONFIGS_GROUP: /* 设置配置 */ pinconf_apply_setting(setting); ops->pin_config_group_set(...); }

参考链接:

pinctrl 子系统介绍_pinctrl子系统_kenny_wju的博客-CSDN博客

Linux内核中的GPIO系统之(3):pin controller driver代码分析



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3